﻿//------------------------------------------------------------------------------
// <copyright file="MainWindow.xaml.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace Microsoft.Samples.Kinect.ColorBasics
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using Microsoft.Kinect;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// Active Kinect sensor
        /// </summary>
        private KinectSensor sensor;

        /// <summary>
        /// Bitmap that will hold color information
        /// </summary>
        private WriteableBitmap colorBitmap;

        /// <summary>
        /// Intermediate storage for the color data received from the camera
        /// </summary>
        private byte[] colorPixels;
        private byte[] colorPixels2;

        private int pixelno;
        private DepthImagePixel[] depthPixels;
        private int lastSmallesDepth;

        /// <summary>
        /// Initializes a new instance of the MainWindow class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Execute startup tasks
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            // Look through all sensors and start the first connected one.
            // This requires that a Kinect is connected at the time of app startup.
            // To make your app robust against plug/unplug, 
            // it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit (See components in Toolkit Browser).
            foreach (var potentialSensor in KinectSensor.KinectSensors)
            {
                if (potentialSensor.Status == KinectStatus.Connected)
                {
                    this.sensor = potentialSensor;
                    break;
                }
            }

            if (null != this.sensor)
            {
                // Turn on the color stream to receive color frames
                this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);

                // Allocate space to put the pixels we'll receive
                this.colorPixels = new byte[this.sensor.ColorStream.FramePixelDataLength];
                this.colorPixels2 = new byte[this.sensor.ColorStream.FramePixelDataLength];

                // Turn on the depth stream to receive depth frames
                this.sensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);

                // Allocate space to put the depth pixels we'll receive
                this.depthPixels = new DepthImagePixel[this.sensor.DepthStream.FramePixelDataLength];

                // This is the bitmap we'll display on-screen
                this.colorBitmap = new WriteableBitmap(this.sensor.ColorStream.FrameWidth, this.sensor.ColorStream.FrameHeight, 96.0, 96.0, PixelFormats.Bgr32, null);

                // Set the image we display to point to the bitmap where we'll put the image data
                this.Image.Source = this.colorBitmap;

                // Add an event handler to be called whenever there is new color frame data
                this.sensor.ColorFrameReady += this.SensorColorFrameReady;
                this.sensor.DepthFrameReady += this.SensorDepthFrameReady;

                // Start the sensor!
                try
                {
                    this.sensor.Start();
                }
                catch (IOException)
                {
                    this.sensor = null;
                }
            }

            if (null == this.sensor)
            {
                this.statusBarText.Text = Properties.Resources.NoKinectReady;
            }
        }

        /// <summary>
        /// Execute shutdown tasks
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (null != this.sensor)
            {
                this.sensor.Stop();
            }
        }

        private void SensorDepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
            {
                if (depthFrame != null)
                {
                    // Copy the pixel data from the image to a temporary array
                    depthFrame.CopyDepthImagePixelDataTo(this.depthPixels);

                    // Get the min and max reliable depth for the current frame
                    int minDepth = depthFrame.MinDepth;
                    int maxDepth = depthFrame.MaxDepth;

                    int smallestDepth = 100000;
                    int newpixelno = 0;

                    for (int i = 0; i < this.depthPixels.Length; ++i)
                    {
                        // Get the depth for this pixel
                        short depth = depthPixels[i].Depth;
                        if (depthPixels[i].IsKnownDepth)
                            if (depth != 0 & depth < smallestDepth)
                            {
                                smallestDepth = depth;
                                newpixelno = i;
                            }
                    }

                    int oldrow = pixelno / depthFrame.Width;
                    int oldcol = pixelno - oldrow * depthFrame.Width;

                    int newrow = newpixelno / depthFrame.Width;
                    int newcol = newpixelno - newrow * depthFrame.Width;

                    if ((Math.Abs(oldrow - newrow) < 5 & Math.Abs(oldcol - newcol) < 5) |
                        Math.Abs(smallestDepth - lastSmallesDepth) > 3)
                    {
                        pixelno = newpixelno;
                        lastSmallesDepth = smallestDepth;
                    }
                }
            }
        }

        /// <summary>
        /// Event handler for Kinect sensor's ColorFrameReady event
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    // Copy the pixel data from the image to a temporary array
                    colorFrame.CopyPixelDataTo(this.colorPixels);

                    // pixelno = (int)(colorBitmap.Height * colorBitmap.Width);
                    int BlankOutWidth = (int) colorFrame.Width / 4;
                    int BlankOutHeight = (int) colorFrame.Height / 4;

                    int StartRow = (int)(pixelno / colorFrame.Width);
                    int StartCol = (int)(pixelno - (StartRow * colorFrame.Width));

                    StartRow -= BlankOutHeight / 2;
                    StartCol -= BlankOutWidth / 2;

                    if (StartRow < 0)
                        StartRow = 0;
                    if (StartRow > colorFrame.Height - BlankOutHeight)
                        StartRow = colorFrame.Height - BlankOutHeight;

                    if (StartCol < 0)
                        StartCol = 0;
                    if (StartCol > colorFrame.Width - BlankOutWidth)
                       StartCol = colorFrame.Width - BlankOutWidth;

                    DebugOutput.Text =
                        pixelno.ToString() + " @ " +
                        colorFrame.Width.ToString() + " * " +
                        colorFrame.Height.ToString() + " = " +
                        (colorFrame.Height * colorFrame.Width).ToString() + " / " +
                        StartCol.ToString() + " * " +
                        StartRow.ToString() + " - " +
                        BlankOutWidth.ToString() + " * " +
                        BlankOutHeight.ToString();

                    int Idx;
                    
                    for (int i = StartRow; i < (StartRow + BlankOutHeight); i++)
                        for (int j = StartCol; j < (StartCol + BlankOutWidth); j++)
                            for (int k = 0;k<4;k++)
                        {
                            Idx = (int)((i * colorFrame.Width * 4) + j * 4 + k);
                            if (Idx < colorPixels.GetLength(0))
                            {
                                int Idx2 = (int)(((i -StartRow) * colorFrame.Width * 4) + (j - StartCol) * 4 + k);
                                this.colorPixels2[Idx2] = this.colorPixels[Idx];
                                this.colorPixels[Idx2] = this.colorPixels[Idx];
                                this.colorPixels[Idx] -= 50;
                                if (this.colorPixels[Idx] < 0)
                                    this.colorPixels[Idx] = 0;
                            }
                        }
                   

                    // Write the pixel data into our bitmap
                    this.colorBitmap.WritePixels(
                        new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
                        this.colorPixels,
                        this.colorBitmap.PixelWidth * sizeof(int),
                        0);
                }
            }
        }

        /// <summary>
        /// Handles the user clicking on the screenshot button
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void ButtonScreenshotClick(object sender, RoutedEventArgs e)
        {
            if (null == this.sensor)
            {
                this.statusBarText.Text = Properties.Resources.ConnectDeviceFirst;
                return;
            }

            // create a png bitmap encoder which knows how to save a .png file
            BitmapEncoder encoder = new PngBitmapEncoder();

            // create frame from the writable bitmap and add to encoder
            encoder.Frames.Add(BitmapFrame.Create(this.colorBitmap));

            string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);

            string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

            string path = Path.Combine(myPhotos, "KinectSnapshot-" + time + ".png");

            // write the new file to disk
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.Create))
                {
                    encoder.Save(fs);
                }

                this.statusBarText.Text = string.Format("{0} {1}", Properties.Resources.ScreenshotWriteSuccess, path);
            }
            catch (IOException)
            {
                this.statusBarText.Text = string.Format("{0} {1}", Properties.Resources.ScreenshotWriteFailed, path);
            }
        }
    }
}